package com.sun.springsecruity.config;

import com.sun.springsecruity.service.PasswordEncoderServiceImpl;
import com.sun.springsecruity.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;

@Configuration
@EnableWebSecurity
public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private UserDetailsServiceImpl detailsService;

    //    @Autowired
//    private PasswordEncoderServiceImpl passwordEncoderService;
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
//    /**
//     * 配置为无需加密，此方法在5.0以上已弃用，要求必须有默认的PasswordEncoder
//     * 这里只做演示需要暂用
//     */
//    @Bean
//    public static NoOpPasswordEncoder passwordEncoder() {
//        return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
//    }

    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {
//        //super.configure(auth); 一定要禁用默认规则
//        builder.inMemoryAuthentication()
//                .withUser("tom")
//                .password("123123")     //设置账号密码
//                .roles("ADMIN","学徒","宗师")   //设置角色
//                .and()
//                .withUser("jerry")
//                .password("456456")  //设置另一个账号密码
//                .authorities("SAVE", "EDIT"); //设置权限
        //装配UerDetailsService
        builder.userDetailsService(detailsService).passwordEncoder(passwordEncoder);
    }

    @Override
    protected void configure(HttpSecurity security) throws Exception {
        JdbcTokenRepositoryImpl repository = new JdbcTokenRepositoryImpl();
        repository.setDataSource(dataSource);

        //super.configure(security); 注释掉将取消父类方法中的默认规则
        security.authorizeRequests()  //对请求进行授权
                .antMatchers("/layui/**", "/index.jsp")  //使用 ANT 风格设置要授权的 URL 地 址
                .permitAll()                        //允许上面使用 ANT 风格设置的全部请求
                .antMatchers("/level1/**") .hasRole("学徒")
                .antMatchers("/level2/**") .hasRole("大师")
                .antMatchers("/level3/**") .hasRole("宗师")
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()                       //设置未授权请求跳转到登录页面
                .loginPage("/index.jsp")          //指定登录页
                .loginProcessingUrl("/do/login.html")
                .usernameParameter("loginAcct")   // 定制登录账号的请求参数名
                .passwordParameter("userPswd")    // 定制登录密码的请求参数名
                .defaultSuccessUrl("/main.html") //设置登录成功后默认前往的 URL 地址
                .and()
                //.csrf()
                //.disable()                      //禁用csfr
                .logout()
                .logoutUrl("/do/logout.html")
                .logoutSuccessUrl("/")
                .and()
                .exceptionHandling()        //指定异常处理器
                //.accessDeniedPage("/to/no/auth/page.html")   //访问被拒绝时前往的页面
                .accessDeniedHandler(new AccessDeniedHandler() {
                    //自定义错误处理方法
                    @Override
                    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
                        httpServletRequest.setAttribute("message","抱歉没有访问资源的权限");
                        httpServletRequest.getRequestDispatcher("/WEB-INF/views/no_auth.jsp").forward(httpServletRequest,httpServletResponse);
                    }
                })
                .and()
                .rememberMe()
                .tokenRepository(repository)
        ;
    }
}

